-- ======================================================================
-- Hell Lua Bus
-- 
-- Copyright 2013 Hell-Prototypes
--
-- http://www.hellprototypes.com/
--
-- This is free software, licensed under the terms of the GNU General
-- Public License as published by the Free Software Foundation.
-- ======================================================================
hlb = require('libhlb')

XVSF_TCK = 0
XVSF_TMS = 1
XVSF_TDI = 2
XVSF_TDO = 3

byte_mask = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}

g_xvsf_file_data = ""
g_xvsf_file_data_index = 1

g_feed = 0
g_percent = 0
g_last_percent = -1

g_start_time = 0
-- -----------------------------------------------------------------------------
XSVF_ERROR_NONE         = 0
--[[
XSVF_ERROR_UNKNOWN      1
XSVF_ERROR_TDOMISMATCH  2
XSVF_ERROR_MAXRETRIES   3   /* TDO mismatch after max retries */
XSVF_ERROR_ILLEGALCMD   4
XSVF_ERROR_ILLEGALSTATE 5
XSVF_ERROR_DATAOVERFLOW 6   /* Data > lenVal MAX_LEN buffer size*/
--]]
-- -----------------------------------------------------------------------------
function port_init()
	local ret
	local init_io_data = 0
	local init_oe_data = byte_mask[XVSF_TCK+1] + byte_mask[XVSF_TMS+1] + byte_mask[XVSF_TDI+1]
    -- XVSF_TDO is input

	ret = hlb.port_write(init_io_data)
	if ret < 0 then
		print("<XVSF> port_init : hlb_port_write ret = ", ret)
		return false
	end
	
	ret = hlb.port_oe(init_oe_data)
	if ret < 0 then
		print("<XVSF> port_init : hlb_port_oe ret = ", ret)
		return false
	end
    
    return true
end
-- -----------------------------------------------------------------------------
function get_TDO()
	return hlb.get_bit(XVSF_TDO)
end

function pin_set(pin)
	local ret = hlb.set_bit( pin )
	if ret < 0 then
		print("<XVSF> Pin" .. pin .." : hlb_set_bit ret = ", ret)
	end
end

function pin_reset( pin )
	local ret = hlb.clr_bit( pin )
	if ret < 0 then
		print("<XVSF> Pin" .. pin .." : hlb_clr_bit ret = ", ret)
	end
end
-- -----------------------------------------------------------------------------
function device_open()
	local ret = hlb.usb_open(0x04B4FFFF)
	if ret < 0 then
		return false
	end
	
	return true
end

function device_close()
	local ret = hlb.usb_close()
	if ret < 0 then
		return false
	end
	
	return true
end
-- -----------------------------------------------------------------------------
function Read_File(file_name)
    local content = ""
    local file = io.open(file_name, "rb") --read file with binary mode
    
    if file == nil then
        print("fail to open file: " .. file_name)
        return content
    end
    content = file:read("*all")
    file:close()
    
	return content
end
-- =============================================================================
function callback_setPort(port, value)
    --print("callback_setPort, port=" .. port .. ", value=" .. value)
    -- Port define: 0: TCK, 1: TMS, 2: TDI
    if value > 0 then
        if port == 0 then
            pin_set(XVSF_TCK)
        elseif port == 1 then
            pin_set(XVSF_TMS)
        elseif port == 2 then
            pin_set(XVSF_TDI)
        end
    else
        if port == 0 then
            pin_reset(XVSF_TCK)
        elseif port == 1 then
            pin_reset(XVSF_TMS)
        elseif port == 2 then
            pin_reset(XVSF_TDI)
        end
    end 
end
-- -----------------------------------------------------------------------------
function callback_readTDOBit()
    local ret = get_TDO()

    --print("--- callback_readTDOBit")
    if type(ret) ~= "boolean" then
        print("<XVSF> get_TDO command fail, ERR Code = " .. ret)
        ret = 0
    else
        if ret == true then
            ret = 1
        else
            ret = 0
        end
    end

    return ret
end
-- -----------------------------------------------------------------------------
function callback_readByte()
    local read = 0
    local one_byte_time = 0
    local data_len = g_xvsf_file_data:len()

    if g_xvsf_file_data_index <= data_len then
        read = g_xvsf_file_data:byte(g_xvsf_file_data_index)
        g_xvsf_file_data_index = g_xvsf_file_data_index + 1

        g_percent = (math.floor((1000*g_xvsf_file_data_index)/data_len))/10
        if g_xvsf_file_data_index % 170 == 0 then
            one_byte_time = (os.time() - g_start_time)/g_xvsf_file_data_index;
            print("# " .. string.format("%4.1f%%, ", g_percent) .. g_xvsf_file_data_index .. "B of " .. data_len .. "B have sent,\tAbout ".. math.floor(one_byte_time * g_xvsf_file_data_index) .. "S runned, Remaining " .. math.floor(one_byte_time * (data_len - g_xvsf_file_data_index)) .. "S")
        end
    end
    --print("--- callback_readByte, read = " .. read)

    return read
end
-- -----------------------------------------------------------------------------

g_xvsf_file_data = Read_File("led_test.xsvf")
g_xvsf_file_data_index = 1

if g_xvsf_file_data:len() == 0 then
    print("<XVSF> No data to download, exit")
    return
end

if device_open() == false then
    print("Fail to open usb")
    return
end

if port_init() == false then
    print("Fail to Init Port")
    device_close()
    return
end
g_start_time = os.time()
print("Start program XSVF, " .. #g_xvsf_file_data .. "bytes need to write")
ret = hlb.xsvf_process(callback_readByte, callback_readTDOBit, callback_setPort)
print("")
if ret == XSVF_ERROR_NONE then
    print("<XVSF> Work DONE ...")
    print("<XVSF> Use up " .. os.time() - g_start_time .. " Second")
else
    print("<XVSF> Work FAIL, Error Code = " .. ret)
end

device_close()
